package main

import (
	"encoding/json"
	"fmt"
	"io"
	"os"

	"github.com/spf13/viper"
	"gopkg.in/yaml.v3"
)

var (
	v       *viper.Viper
	gconfig Config
)

func init() {
	// 使用viper管理配置文件。
	// https://zhuanlan.zhihu.com/p/272508571
	v = viper.GetViper()
	// 设置默认配置文件名字:godemo，以及三个默认搜索路径
	v.SetConfigFile("godemo.json")
	v.AddConfigPath("/etc/godemo.json")
	v.AddConfigPath("$HOME/.godemo.json")
	v.AddConfigPath("./godemo.json")

}

// LogConfig 和日志有关的配置信息
type LogConfig struct {
	Output string `yaml:",omitempty" json:"output,omitempty"`
	Level  string `yaml:",omitempty" json:"level,omitempty"`
	Format string `yaml:",omitempty json:format,omitempty"`
}

// DatabaseConfig 和DB有关的配置信息
type DatabaseConfig struct {
	MongoDBIP   string `yaml:",omitempty" json:"mongodbip,omitempty"`
	MongoDBPort int    `yaml:",omitempty" json:"mongodbport,omitempty"`
}

// Config 和配置文件对应的配置对象。
type Config struct {
	Log      *LogConfig      `yaml:"omitempty" json:"log,omitempty"`
	Database *DatabaseConfig `yaml:"omitempty" json:"database,omitemtpy"`
}

// Load 从预定义的几个配置文件目录中寻找并加载配置。
func (c *Config) Load() error {
	if err := v.ReadInConfig(); err != nil {
		return err
	}
	return v.Unmarshal(c)
}

// Read 从指定的io.Reader中读取配置。
func (c *Config) Read(r io.Reader) error {
	if err := v.ReadConfig(r); err != nil {
		return err
	}
	return v.Unmarshal(c)
}

// ReadFile 从指定的文件中读取配置。
func (c *Config) ReadFile(file string) error {
	v.SetConfigFile(file)
	if err := v.ReadInConfig(); err != nil {
		return err
	}
	return v.Unmarshal(c)
}

// Write 这个函数将当前配置以format参数指定的格式写入到一个io.Writer中（写文件，写缓冲区等）
func (c *Config) Write(w io.Writer, format string) error {
	switch format {
	case "json":
		enc := json.NewEncoder(w)
		enc.SetIndent("", "  ")
		enc.Encode(c)
		return nil
	case "yaml":
		fallthrough
	default:
		enc := yaml.NewEncoder(w)
		defer enc.Close()
		return enc.Encode(c)
	}
}

// getConfigFilePath 获取当前使用的配置文件的路径。
func (c *Config) GetConfigFilePath() string {
	return v.ConfigFileUsed()
}

func main() {
	if err := gconfig.Load(); err != nil {
		fmt.Printf("加载配置错误%s\n", err.Error())
	} else {
		fmt.Printf("当前配置:%s\n", gconfig.GetConfigFilePath())
		gconfig.Write(os.Stdout, "json")
	}
}
